package edu.bu.cs673.superkids123.common.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.OneToMany;

import edu.bu.cs673.superkids123.children.model.Activity;
import edu.bu.cs673.superkids123.children.model.CompletedGame;
import edu.bu.cs673.superkids123.children.model.CompletedLesson;
import edu.bu.cs673.superkids123.children.model.Level;
import edu.bu.cs673.superkids123.children.model.PlayTime;
import edu.bu.cs673.superkids123.children.model.resources.ChildrenResource;
import edu.bu.cs673.superkids123.children.model.resources.ResourceType;
import edu.bu.cs673.superkids123.parents.model.Image;
import edu.bu.cs673.superkids123.parents.model.SystemTheme;


import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.JoinColumn;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;

@Entity
@Table(name="Children")
@PrimaryKeyJoinColumn(name="UserID")
public class Child extends User {

	
	
	@Column(name="Age")
	private int age;
	
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Column(name="Sex")
	private Sex sex = Sex.Blank;
	
	@Column(name="PlayTimePerDay", nullable=false, columnDefinition="int default 0")
	private int playTimePerDay = 0;

	@ManyToMany(fetch=FetchType.EAGER)
	@Cascade({CascadeType.ALL})
	@JoinTable(name = "Child_Achievements", joinColumns = @JoinColumn(name = "UserID") , inverseJoinColumns = @JoinColumn(name = "AchievementsID"))
	private Set<Achievement> achievements = new HashSet<Achievement>();
	
	@ManyToOne
	@Cascade({CascadeType.SAVE_UPDATE})
	@NotFound(action=NotFoundAction.IGNORE)
	@JoinColumn(name="ImageID")
	private Image image = null;
	
	@ManyToOne
	@Cascade({CascadeType.SAVE_UPDATE})
	@NotFound(action=NotFoundAction.IGNORE)
	@JoinColumn(name="ThemeID")
	private SystemTheme systemTheme;

	@ManyToOne
	@NotFound(action=NotFoundAction.IGNORE)
	@Cascade({CascadeType.SAVE_UPDATE})
	@JoinColumn(name="LevelID")
	private Level level;
	
	@OneToMany(mappedBy="child",fetch=FetchType.LAZY,orphanRemoval=true)
	@Cascade({CascadeType.ALL})
	@NotFound(action=NotFoundAction.IGNORE)
	private Set<PlayTime> playTimes = new HashSet<PlayTime>();

	@Enumerated(EnumType.STRING)
	private ResourceType imageResource;
	
	private ResourceType audioResource;
	
	private ResourceType stringResource;
	
	// Sets (for database relations)
	
	@OneToMany(mappedBy="child")
	private Set<Activity> activities = new HashSet<Activity>();
	
	@OneToMany(mappedBy="child",fetch=FetchType.EAGER)
	@Cascade({CascadeType.ALL})
	@NotFound(action=NotFoundAction.IGNORE)
	private Set<CompletedLesson> CompletedLesson = new HashSet<CompletedLesson>();
	
	@OneToMany(mappedBy="child",fetch=FetchType.EAGER)
	@Cascade({CascadeType.ALL})
	@NotFound(action=NotFoundAction.IGNORE)
	private Set<CompletedGame> CompletedGames = new HashSet<CompletedGame>();
	
	// Setters and Getters
	
	public Set<Activity> getActivities() {
		return activities;
	}

	public Set<CompletedGame> getCompletedGames() {
		return CompletedGames;
	}

	public void setCompletedGames(Set<CompletedGame> completedGames) {
		CompletedGames = completedGames;
	}

	public void setActivities(Set<Activity> activities) {
		this.activities = activities;
	}

	public Set<CompletedLesson> getCompletedLesson() {
		return CompletedLesson;
	}

	public void setCompletedLesson(Set<CompletedLesson> completedLesson) {
		CompletedLesson = completedLesson;
	}

	public Level getLevel() {
		return level;
	}

	public void setLevel(Level level) {
		this.level = level;
	}

	public ResourceType getImageResource() {
		
		if (imageResource == null)
			imageResource = ResourceType.Default;
		
		return imageResource;
	}

	public void setImageResource(ResourceType imageResource) {
		this.imageResource = imageResource;
	}

	public ResourceType getAudioResource() {
		
		if (audioResource == null)
			audioResource = ResourceType.Default;
		
		return audioResource;
	}

	public void setAudioResource(ResourceType audioResource) {
		this.audioResource = audioResource;
	}

	public ResourceType getStringResource() {
		
		if (stringResource == null)
			stringResource = ResourceType.Default;
		
		return stringResource;
	}

	public void setStringResource(ResourceType stringResource) {
		this.stringResource = stringResource;
	}

	public SystemTheme getSystemTheme() {
		return systemTheme;
	}

	public void setSystemTheme(SystemTheme systemTheme) {
		this.systemTheme = systemTheme;
	}

	public Image getImage() {
		
		if (image == null) {
			image = new Image();
			image.setFileName(ChildrenResource.imageQuestionMark);
		}
		
		return image;
	}

	public void setImage(Image image) {
		this.image = image;
	}

	public Set<Achievement> getAchievements() {
		return achievements;
	}

	public void setAchievements(Set<Achievement> achievments) {
		this.achievements = achievments;
	}

	public boolean isActive() {
		return isActive;
	}

	public void setActive(boolean isActive) {
		this.isActive = isActive;
	}
	@Column(name="IsLocked")
	private boolean isLocked = false;

	public boolean isLocked() {
		return isLocked;
	}

	public void setLocked(boolean lock) {
		this.isLocked = lock;
	}

	@Column(name="IsActive")
	private boolean isActive;
	
	public Set<PlayTime> getPlayTimes() {
		return playTimes;
	}
	
	public void setPlayTimes(Set<PlayTime> playTimes) {
		this.playTimes = playTimes;
	}
	
		
	public Child() {
		setSex(Sex.Female);
		setAge(2);
	}
	
	// Instance Methods

	public Sex getSex() {
		return sex;
	}

	public void setSex(Sex sex) {
		this.sex = sex;
	}
	
	public int getPlayTimePerDay() {
		return playTimePerDay;
	}

	public void setPlayTimePerDay(int playTimePerDay) {
		this.playTimePerDay = playTimePerDay;
	}
	
	@Override
	public boolean equals(Object obj) {
		
		if (obj instanceof Child) {
			if (this.getName().equals(((Child)obj).getName()))
				return true;			
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return this.getId();
	}

	public enum Sex {
		Blank, Male, Female
	}

	public enum Age {
		select, Two, Three, Four, Five
	}
	public void setAge(Age age) {
		switch (age) {
		case Two:
			this.age = 2;
			break;
		case Three:
			this.age = 3;
			break;
		case Four:
			this.age = 4;
			break;
		case Five:
			this.age = 5;
			break;
		default:
			System.err.println("Unknown age!");
			break;
		}
	}
	 
	public void addCompletedLesson(CompletedLesson cl)
	{
		cl.setChild(this);
		CompletedLesson.add(cl);
	}
	public void addCompletedGame(CompletedGame cg)
	{
		cg.setChild(this);
		CompletedGames.add(cg);
	}
	
	@Override
	public String toString() {
		return getName();
	}
}
